#include "qemu/osdep.h"
#include "qapi/error.h" /* provides error_fatal() handler */
#include "hw/sysbus.h" /* provides all sysbus registering func */
#include "hw/misc/custom_rom.h"

#include "hw/qdev-core.h"
#include "exec/memory.h"
#include "qemu/log.h"
#include "sysemu/sysemu.h"
#include "qemu/mmap-alloc.h"
#include "qemu/timer.h"
#include "hw/irq.h"
#include "fcntl.h"
#include "unistd.h"

#define TYPE_CUSTOM_ROM "custom_rom"
typedef struct CustomRomState CustomRomState;
DECLARE_INSTANCE_CHECKER(CustomRomState, CUSTOM_ROM, TYPE_CUSTOM_ROM)

#define REG_ID 	0x0
#define CHIP_ID	0xBA000001

struct CustomRomState {
	SysBusDevice parent_obj;
	MemoryRegion iomem;
	uint64_t chip_id;
	 volatile uint32_t *shared_memory;
     qemu_irq irq;
     int irq_line;
};

static void check_irq(void *opaque) {
    CustomRomState *s = opaque;

    if (s->shared_memory[8]) {
        // 检测到共享内存变化，触发中断
        qemu_log("qemu Interrupt triggered due to shared memory change.\n");
        s->shared_memory[8] = 0;
        // qemu_set_irq(s->irq, 1);
        // qemu_set_irq(s->irq, 0);  // 清除中断信号
        qemu_irq_raise(s->irq);
        
    }
}

static uint64_t custom_rom_read(void *opaque, hwaddr addr, unsigned int size)
{
	qemu_log("qemu read start\n");
	CustomRomState *s = opaque;
	s->shared_memory[6] = addr;
	s->shared_memory[4] = 1; //rdvld
	s->shared_memory[5] = 0;
	while(s->shared_memory[5] == 0); //rdrdy
	s->shared_memory[4] = 0;
	s->shared_memory[5] = 0;
	qemu_log("qemu read end\n");
	return s->shared_memory[7];

}

static void custom_rom_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
{
	qemu_log("qemu write start\n");
	CustomRomState *s = opaque;
	s->shared_memory[2] = addr;
	s->shared_memory[3] = value;
	s->shared_memory[0] = 1; //rdvld
	s->shared_memory[1] = 0;
	while(s->shared_memory[1] == 0); //rdrdy
	s->shared_memory[0] = 0;
	s->shared_memory[1] = 0;
	qemu_log("qemu write end\n");
	
}

static const MemoryRegionOps custom_rom_ops = {
	.read = custom_rom_read,
	.write = custom_rom_write,
	.endianness = DEVICE_NATIVE_ENDIAN,
};

static void custom_rom_instance_init(Object *obj)
{
	CustomRomState *s = CUSTOM_ROM(obj);

	/* allocate memory map region */
	memory_region_init_io(&s->iomem, obj, &custom_rom_ops, s, TYPE_CUSTOM_ROM, 0x100);
	sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);

	s->chip_id = CHIP_ID;
	s->irq_line = 0x13;
    // 初始化中断线路
    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
    // s->irq_line = qemu_irq_get_index(s->irq);
    qemu_log("qemu init irq = %d\n", s->irq_line);

    // 设置定期检查共享内存变化的计时器
    QEMUTimer *timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, check_irq, s); // 每1ms
    timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); // 100ms 后触发

	// 创建共享内存
    int shm_fd = shm_open("my_shm", O_RDWR, 0666);
    //int shm_fd = shm_open("my_shm", O_CREAT | O_RDWR, 0666);
    int ret = ftruncate(shm_fd, 0x1000);  // 共享内存大小为 4KB
    if(ret) qemu_log("ftruncate fail");
    s->shared_memory = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    close(shm_fd);	
}

/* create a new type to define the info related to our device */
static const TypeInfo custom_rom_info = {
	.name = TYPE_CUSTOM_ROM,
	.parent = TYPE_SYS_BUS_DEVICE,
	.instance_size = sizeof(CustomRomState),
	.instance_init = custom_rom_instance_init,
};

static void custom_rom_register_types(void)
{
    type_register_static(&custom_rom_info);
}

type_init(custom_rom_register_types)

/*
 * Create the Custom Rom device.
 */
DeviceState *custom_rom_create(hwaddr addr)
{
	DeviceState *dev = qdev_new(TYPE_CUSTOM_ROM);
	sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
	sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);

    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    DeviceState *plic = DEVICE(object_resolve_path("/machine/unattached/device[2]", NULL));
    if (!plic) {
        qemu_log("PLIC device not found");
    }
    sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(plic, 0x13));
	return dev;
}
